package com.coldwindblows.blog.service.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.coldwindblows.blog.bo.ArchiveBo;
import com.coldwindblows.blog.bo.BackResponseBo;
import com.coldwindblows.blog.bo.StatisticsBo;
import com.coldwindblows.blog.constant.WebConst;
import com.coldwindblows.blog.controller.admin.AttachController;
import com.coldwindblows.blog.dao.AttachMapper;
import com.coldwindblows.blog.dao.CommentMapper;
import com.coldwindblows.blog.dao.ContentMapper;
import com.coldwindblows.blog.dao.MetaMapper;
import com.coldwindblows.blog.dto.MetaDto;
import com.coldwindblows.blog.dto.Types;
import com.coldwindblows.blog.exception.TipException;
import com.coldwindblows.blog.pojo.CommentDo;
import com.coldwindblows.blog.pojo.ContentDo;
import com.coldwindblows.blog.pojo.MetaDo;
import com.coldwindblows.blog.service.ISiteService;
import com.coldwindblows.blog.utils.TaleUtils;
import com.coldwindblows.blog.utils.TimeUtil;
import com.coldwindblows.blog.utils.ZipUtils;
import com.coldwindblows.blog.utils.backup.Backup;
import com.github.pagehelper.PageHelper;

/**
 * Created by ColdWindBlows on 2018/07/04
 *
 */
@Service
public class ISiteServiceImpl implements ISiteService {

	@Autowired
	private CommentMapper commentDao;
	
	@Autowired
	private ContentMapper contentDao;
	
	@Autowired
	private AttachMapper attachDao;
	
	@Autowired
	private MetaMapper metaDao;
	
	@Override
	public List<CommentDo> recentComments(int limit) {
		limit = limit < 0 || limit > 10 ? 10 : limit;
		PageHelper.startPage(1, limit);
		return commentDao.listAll();
	}

	@Override
	public List<ContentDo> recentContents(int limit) {
		limit = limit < 0 || limit > 10 ? 10 : limit;
		PageHelper.startPage(1, limit);
		return contentDao.listAll();
	}

	@Override
	public CommentDo getComment(Integer coid) {
		if(null != coid) {
			return commentDao.selectByPrimaryKey(coid);
		}
		return null;
	}

	@Override
	public BackResponseBo backup(String bkType, String bkPath, String fmt) throws Exception {
		BackResponseBo backResponse = new BackResponseBo();
		if(bkType.equals("attach")) {
			if(StringUtils.isBlank(bkPath)) {
				throw new TipException("请输入备份文件存储路径");
			}
			if(!(new File(bkPath).isDirectory())) {
				throw new TipException("请输入一个存在的目录");
			}
			
			String bkAttachDir = AttachController.CLASSPATH + "upload";
			String bkThemesDir = AttachController.CLASSPATH + "templates/themes";
			
			String fname = TimeUtil.toTime(new Date(), fmt) + "_" + TaleUtils.getRandomNumber(5) + ".zip";
			
			String attachPath = bkPath + "/" + "attachs_" + fname;
			String themesPath = bkPath + "/" + "themes_" + fname;
			
			ZipUtils.zipFoler(bkAttachDir, attachPath);
			ZipUtils.zipFoler(bkThemesDir, themesPath);
			
			backResponse.setAttachPath(attachPath);
			backResponse.setThemePath(themesPath);
		}
		
		if(bkType.equals("db")) {
			String bkAttachDir = AttachController.CLASSPATH + "upload/";
			if(!(new File(bkAttachDir).isDirectory())) {
				File file = new File(bkAttachDir);
				if(!file.exists()) {
					file.mkdirs();
				}
			}
			
			String sqlFileName = "tale_" + TimeUtil.toTime(new Date(), fmt) + "_" + TaleUtils.getRandomNumber(5) + ".sql";
			String zipFile = sqlFileName.replace(".sql", ".zip");
			
			Backup backup = new Backup(TaleUtils.getNewDataSource().getConnection());
			String sqlContent = backup.execute();
			
			File sqlFile = new File(bkAttachDir + sqlFileName);
			write(sqlContent, sqlFile, Charset.forName("UTF-8"));
			
			String zip = bkAttachDir + zipFile;
			ZipUtils.zipFile(sqlFile.getPath(), zip);
			
			if(!sqlFile.exists()) {
				throw new TipException("数据库备份失败");
			}
			
			sqlFile.delete();
			
			backResponse.setSqlPath(zipFile);
			
			// 10秒后删除备份文件
			new Timer().schedule(new TimerTask() {
				
				@Override
				public void run() {
					new File(zip).delete();
				}
			}, 10 * 1000);
		}
		
		return backResponse;
	}

	@Override
	public StatisticsBo getStatistics() {
		StatisticsBo statistics = new StatisticsBo();
		
		ContentDo temp = new ContentDo();
		temp.setType(Types.ARTICLE.getType());
		temp.setStatus(Types.PUBLISH.getType());
		Long articles = contentDao.countBySelective(temp);
		
		Long comments = commentDao.countAll();
		
		Long attachs = attachDao.countAll();
		
		MetaDo meta = new MetaDo();
		meta.setType(Types.LINK.getType());
		Long links = metaDao.countBySelective(meta);
		
		statistics.setArticles(articles);
		statistics.setComments(comments);
		statistics.setAttachs(attachs);
		statistics.setLinks(links);
		
		return statistics;
	}

	@Override
	public List<ArchiveBo> getArchives() {
		List<ArchiveBo> archives = contentDao.findReturnArchiveBo();
		if(null != archives) {
			archives.forEach(archive -> {
				ContentDo content = new ContentDo();
				content.setType(Types.ARTICLE.getType());
				content.setStatus(Types.PUBLISH.getType());
				String date = archive.getDate();
				Date sd = TimeUtil.stringToDate(date, "yyyy年MM月");
				Date end = TimeUtil.futureMonthTime(sd, 1);
				List<ContentDo> list = contentDao.selectByStartTimeAndEndTime(sd, end);
				archive.setArticles(list);
			});
		}
		return archives;
	}

	@Override
	public List<MetaDto> metas(String type, String orderBy, int limit) {
		List<MetaDto> retList = null;
		if(StringUtils.isNotBlank(type)) {
			if(StringUtils.isBlank(orderBy)) {
				orderBy = "count desc, a.mid desc";
			}
			limit = limit < 1 || limit > WebConst.MAX_POSTS ? 10 : limit;
			MetaDo temp = new MetaDo();
			temp.setType(type);
			retList = metaDao.selectFromSql(temp, orderBy, limit);
		}
		return retList;
	}
	
	private void write(String data, File file, Charset charset) {
		FileOutputStream os = null;
		try {
			os = new FileOutputStream(file);
			os.write(data.getBytes(charset));
		} catch(IOException ioe) {
			throw new IllegalStateException(ioe);
		} finally {
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}
